<?php
/*
 *gitLab的web钩子程序
 *author：zhuqi
 *zhu.cheer@qq.com
 *
 *建议请不要将此程序运用在生产环境，您可以在充分了解了本程序的运行原理后，并对安全性做了充分考量后再做打算
 *
 *参数范例：
 *支持多个git项目
 *array(
		'project'=>'project_name',//git项目名称
		'token'=>'xxxxx',//gitlab上配置的token,用来校验
		'branch_sync'=>'master',//当哪个分支push时触发
		'cmd'=>'',//需要执行的shell脚本；
		
	),
 *
 */
$project_option = array(
	
	array(
		'project'=>'rpojectname',
		'token'=>'xxxxx',
		'branch_sync'=>'master',
		'cmd'=>'/webser/gitMid/gitpull.sh rpojectname master',
	),
);

//日志路径
$log_path = './git_hooker.log';

//什么操作触发 push/tag_push/issue/note/merge_request
$allow_action = array('push_hooks');

//允许谁操作
$allow_user = array(
	'zhu.cheer@qq.com',
);



$hooker = new HookJob($project_option, $log_path, $allow_action, $allow_user);
$hooker->runSync();




class HookJob{
	
	private $option;
	private $log_path = '/home/logs/git_hooker.log';
	private $allow_action = array('push_hooks');
	private $allow_user = '*';
	public function __construct($project_option, $log_path='', $allow_action=array('push_hooks'), $allow_user='*'){
		$this->option = array();
		foreach($project_option as $item){
			$this->option[$item['project'].'#'.$item['branch_sync']] = $item;
		}
		if(!empty($log_path)){
			$this->log_path = $log_path;
		}
		if(!empty($allow_action)){
			$this->allow_action = $allow_action;
		}
		if(!empty($allow_user)){
			$this->allow_user = $allow_user;
		}
		
		if (function_exists('fastcgi_finish_request')) {
            fastcgi_finish_request();
        }
	}
	
	public function runSync(){
		$projectInfo = $this->getProjectInfo();
		$shellCommand = $projectInfo['cmd'];
		
		echo "等待执行---> {$shellCommand}";
		
		if (function_exists("fastcgi_finish_request")) {
			fastcgi_finish_request();
		}
		
		$exec = shell_exec($shellCommand);
		if(empty($exec)){
			$this->throwError('命令执行出现问题,请检查php.ini将shell_exec函数取消禁用！##'.$exec);
		}
		
		echo $exec;
		$this->throwLog('命令执行成功##'.$exec);
	}
	
	private function getHookInfo(){
		//也可以安装pecl_http扩展来获取请求头信息
		$httpBody = json_decode(file_get_contents('php://input'),true);
		
		$token = empty($_SERVER['HTTP_X_GITEE_TOKEN']) ? '' : $_SERVER['HTTP_X_GITEE_TOKEN'];
		if(empty($httpBody)){
			return false;
		}
		
		$hookInfo['project'] = empty($httpBody['repository']['path']) ? '' : $httpBody['repository']['path'];
		$hookInfo['action'] = empty($httpBody['hook_name']) ? '' : $httpBody['hook_name'];
		$hookInfo['token'] = $token;
		$hookInfo['user'] = empty($httpBody['repository']['owner']['email']) ? '' : $httpBody['repository']['owner']['email'];
		$hookInfo['branch_sync'] = empty($httpBody['ref']) ? '' : str_replace('refs/heads/', '', $httpBody['ref']);

		return $hookInfo;
	}
	
	private function getProjectInfo(){
		$hookInfo = $this->getHookInfo();
		
		if(empty($hookInfo)){
			$this->throwError(var_export('无git信息', true));
		}
		
		if(!in_array($hookInfo['action'], $this->allow_action)){
			$this->throwError(var_export('此操作被限制', true));
		}
		if($this->allow_user != '*' && !in_array($hookInfo['user'], $this->allow_user)){
			return $this->throwError('该用户不被允许操作##'.$hookInfo['user']);
		}
		
		if(empty($this->option[$hookInfo['project'].'#'.$hookInfo['branch_sync']])){
			return $this->throwError('未找到同步配置');
		}
		if($this->option[$hookInfo['project'].'#'.$hookInfo['branch_sync']]['token'] != $hookInfo['token']){
			return $this->throwError('同步Token校验失败');
		}
		$projectInfo = $this->option[$hookInfo['project'].'#'.$hookInfo['branch_sync']];
		
		return $projectInfo;
	}
	
	private function throwError($message){
		header("HTTP/1.1 404 Not Found"); 
		$log = '['.date('Y-m-d H:i:s').'] 执行报错:'.$message."\r\n";
		file_put_contents($this->log_path, $log, FILE_APPEND );
		echo $message;
		exit(0);
	}
	
	private function throwLog($message, $level="INFO"){
		header("HTTP/1.1 404 Not Found"); 
		$log = '['.date('Y-m-d H:i:s').'] '.$level.':'.$message."\r\n";
		file_put_contents($this->log_path, $log, FILE_APPEND );
	}
	
}
